Apprenez à créer de puissants points de terminaison d'API avec les Route Handlers de Next.js. Ce guide couvre tout, de la configuration de base aux techniques avancées, avec des exemples pratiques et les meilleures pratiques.
Route Handlers Next.js : Un Guide Complet pour la Création de Points de Terminaison d'API
Next.js a révolutionné la façon dont nous construisons des applications web avec ses fonctionnalités puissantes comme le rendu cÎté serveur, la génération de sites statiques et, maintenant, les Route Handlers. Les Route Handlers offrent un moyen flexible et efficace de créer des points de terminaison d'API directement au sein de votre application Next.js. Ce guide explore le concept des Route Handlers, leurs avantages et comment les utiliser efficacement pour construire des API robustes.
Que sont les Route Handlers de Next.js ?
Les Route Handlers sont des fonctions dĂ©finies dans le rĂ©pertoire app d'un projet Next.js qui traitent les requĂȘtes HTTP entrantes. Contrairement Ă l'ancienne approche pages/api (qui utilise les API Routes), les Route Handlers offrent un moyen plus simple et plus flexible de dĂ©finir des points de terminaison d'API Ă cĂŽtĂ© de vos composants React. Ce sont essentiellement des fonctions sans serveur (serverless) exĂ©cutĂ©es Ă la pĂ©riphĂ©rie (edge) ou dans l'environnement serveur de votre choix.
ConsidĂ©rez les Route Handlers comme la logique backend de votre application Next.js, responsable du traitement des requĂȘtes, de l'interaction avec les bases de donnĂ©es et du renvoi des rĂ©ponses.
Avantages de l'utilisation des Route Handlers
- Colocalisation : Les Route Handlers résident directement à cÎté de vos composants React dans le répertoire
app, favorisant une meilleure organisation et maintenabilité du code. - Support TypeScript : Le support TypeScript intégré garantit la sécurité des types et une meilleure expérience de développement.
- IntĂ©gration de Middleware : IntĂ©grez facilement des middlewares pour des tĂąches telles que l'authentification, l'autorisation et la validation des requĂȘtes.
- Support du Streaming : Les Route Handlers peuvent diffuser des données en continu (streaming), vous permettant d'envoyer des réponses de maniÚre incrémentielle, ce qui est bénéfique pour les grands ensembles de données ou les processus de longue durée.
- Edge Functions : Déployez les Route Handlers en tant que Edge Functions pour des réponses à faible latence, plus proches de vos utilisateurs, en tirant parti des CDN mondiaux.
- Conception d'API simplifiĂ©e : Les Route Handlers fournissent une API claire et intuitive pour la gestion des requĂȘtes et des rĂ©ponses.
- Intégration des Server Actions : L'intégration étroite avec les Server Actions permet une communication transparente entre vos composants cÎté client et la logique cÎté serveur.
Configurer votre projet Next.js
Avant de plonger dans les Route Handlers, assurez-vous d'avoir un projet Next.js configuré avec le répertoire app. Si vous démarrez un nouveau projet, utilisez la commande suivante :
npx create-next-app@latest my-nextjs-app
Choisissez le répertoire app pendant le processus d'installation pour activer le nouveau systÚme de routage.
Créer votre premier Route Handler
Créons un point de terminaison d'API simple qui renvoie une réponse JSON. Créez un nouveau répertoire dans le répertoire app, par exemple, /app/api/hello. à l'intérieur de ce répertoire, créez un fichier nommé route.ts (ou route.js si vous n'utilisez pas TypeScript).
Voici le code de votre premier Route Handler :
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}
Explication :
import { NextResponse } from 'next/server';: Importe l'objetNextResponse, qui est utilisĂ© pour construire les rĂ©ponses de l'API.export async function GET(request: Request) { ... }: DĂ©finit une fonction asynchrone qui gĂšre les requĂȘtes GET vers le point de terminaison/api/hello. Le paramĂštrerequestfournit l'accĂšs Ă l'objet de la requĂȘte entrante.return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });: CrĂ©e une rĂ©ponse JSON avec un message et la renvoie en utilisantNextResponse.json().
Maintenant, vous pouvez accéder à ce point de terminaison en naviguant vers /api/hello dans votre navigateur ou en utilisant un outil comme curl ou Postman.
Gérer les différentes méthodes HTTP
Les Route Handlers prennent en charge diverses mĂ©thodes HTTP comme GET, POST, PUT, DELETE, PATCH et OPTIONS. Vous pouvez dĂ©finir des fonctions distinctes pour chaque mĂ©thode dans le mĂȘme fichier route.ts.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Logique pour récupérer tous les utilisateurs de la base de données
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Données d'exemple
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // Analyser le corps de la requĂȘte en JSON
// Logique pour créer un nouvel utilisateur dans la base de données en utilisant 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // Exemple
return NextResponse.json(newUser, { status: 201 }); // Renvoyer le nouvel utilisateur avec un code de statut 201 Created
}
Explication :
- La fonction
GETrécupÚre une liste d'utilisateurs (simulée ici) et la renvoie sous forme de réponse JSON. - La fonction
POSTanalyse le corps de la requĂȘte en JSON, crĂ©e un nouvel utilisateur (simulĂ©) et renvoie le nouvel utilisateur avec un code de statut 201 Created.
AccĂ©der aux donnĂ©es de la requĂȘte
L'objet request fournit un accĂšs Ă diverses informations sur la requĂȘte entrante, y compris les en-tĂȘtes, les paramĂštres de requĂȘte et le corps de la requĂȘte.
En-tĂȘtes
Vous pouvez accĂ©der aux en-tĂȘtes de la requĂȘte en utilisant la propriĂ©tĂ© request.headers :
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
ParamĂštres de requĂȘte
Pour accĂ©der aux paramĂštres de requĂȘte, vous pouvez utiliser le constructeur URL :
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
Corps de la requĂȘte
Pour les requĂȘtes POST, PUT et PATCH, vous pouvez accĂ©der au corps de la requĂȘte en utilisant les mĂ©thodes request.json() ou request.text(), en fonction du type de contenu.
export async function POST(request: Request) {
const data = await request.json();
console.log('Data:', data);
return NextResponse.json({ receivedData: data });
}
Renvoyer des réponses
L'objet NextResponse est utilisĂ© pour construire les rĂ©ponses de l'API. Il fournit plusieurs mĂ©thodes pour dĂ©finir les en-tĂȘtes, les codes de statut et les corps de rĂ©ponse.
Réponses JSON
Utilisez la méthode NextResponse.json() pour renvoyer des réponses JSON :
return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });
Réponses texte
Utilisez le constructeur new Response() pour renvoyer des réponses en texte brut :
return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
Redirections
Utilisez NextResponse.redirect() pour rediriger les utilisateurs vers une URL différente :
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
DĂ©finir les en-tĂȘtes
Vous pouvez dĂ©finir des en-tĂȘtes personnalisĂ©s en utilisant l'option headers dans NextResponse.json() ou new Response() :
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
Intégration de Middleware
Le middleware vous permet d'exĂ©cuter du code avant qu'une requĂȘte ne soit traitĂ©e par votre Route Handler. C'est utile pour l'authentification, l'autorisation, la journalisation et d'autres prĂ©occupations transversales.
Pour créer un middleware, créez un fichier nommé middleware.ts (ou middleware.js) dans le répertoire app ou n'importe quel sous-répertoire. Le middleware s'appliquera à toutes les routes de ce répertoire et de ses sous-répertoires.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // Appliquer ce middleware aux chemins commençant par /protected/
};
Explication :
- La fonction
middlewarevĂ©rifie la prĂ©sence d'un jeton d'authentification dans les cookies de la requĂȘte. - Si le jeton est manquant, elle redirige l'utilisateur vers la page de connexion.
- Sinon, elle permet Ă la requĂȘte de continuer vers le Route Handler.
- L'objet
configspécifie que ce middleware ne doit s'appliquer qu'aux routes commençant par/protected/.
Gestion des erreurs
Une gestion appropriée des erreurs est cruciale pour construire des API robustes. Vous pouvez utiliser des blocs try...catch pour gérer les exceptions et renvoyer des réponses d'erreur appropriées.
export async function GET(request: Request) {
try {
// Simuler une erreur
throw new Error('Something went wrong!');
} catch (error: any) {
console.error('Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Explication :
- Le bloc
try...catchintercepte toutes les exceptions qui se produisent dans le Route Handler. - Dans le bloc
catch, l'erreur est enregistrée, et une réponse d'erreur est renvoyée avec un code de statut 500 Internal Server Error.
Réponses en streaming
Les Route Handlers prennent en charge les réponses en streaming, ce qui vous permet d'envoyer des données de maniÚre incrémentielle au client. C'est particuliÚrement utile pour les grands ensembles de données ou les processus de longue durée.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simuler un délai
yield `Data chunk ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
Explication :
- La fonction
generateDataest un générateur asynchrone qui produit des morceaux de données avec un délai. - La méthode
Readable.from()crée un flux lisible à partir du générateur. - L'objet
Responseest créé avec le flux lisible comme corps, et l'en-tĂȘteContent-Typeest dĂ©fini surtext/plain.
Authentification et autorisation
La sĂ©curisation de vos points de terminaison d'API est cruciale. Vous pouvez mettre en Ćuvre l'authentification et l'autorisation en utilisant un middleware ou directement dans vos Route Handlers.
Authentification
L'authentification vĂ©rifie l'identitĂ© de l'utilisateur qui effectue la requĂȘte. Les mĂ©thodes d'authentification courantes incluent :
- JWT (JSON Web Tokens) : GĂ©nĂ©rer un jeton lors d'une connexion rĂ©ussie et le vĂ©rifier lors des requĂȘtes ultĂ©rieures.
- Authentification basĂ©e sur les sessions : Utiliser des cookies pour stocker les identifiants de session et les vĂ©rifier Ă chaque requĂȘte.
- OAuth : Déléguer l'authentification à un fournisseur tiers comme Google ou Facebook.
Voici un exemple d'authentification JWT utilisant un middleware :
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // Remplacez par un secret fort généré aléatoirement
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
Autorisation
L'autorisation détermine à quelles ressources un utilisateur est autorisé à accéder. Ceci est généralement basé sur des rÎles ou des permissions.
Vous pouvez mettre en Ćuvre l'autorisation dans vos Route Handlers en vĂ©rifiant les rĂŽles ou les permissions de l'utilisateur et en renvoyant une erreur s'il n'a pas l'accĂšs.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Supposons que vous ayez une fonction pour obtenir le rĂŽle de l'utilisateur Ă partir du jeton ou de la session
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
}
// Logique pour récupérer les données de l'administrateur
const adminData = { message: 'Admin data' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// Remplacez par votre logique rĂ©elle pour extraire le rĂŽle de l'utilisateur de la requĂȘte
// Cela pourrait impliquer la vérification d'un jeton JWT ou la vérification d'une session
return 'admin'; // Exemple : rÎle codé en dur pour la démonstration
}
Déployer les Route Handlers
Les Route Handlers sont déployés en tant que fonctions sans serveur (serverless) sur le fournisseur d'hébergement de votre choix. Next.js prend en charge diverses plateformes de déploiement, notamment Vercel, Netlify, AWS, et plus encore.
Pour Vercel, le déploiement est aussi simple que de connecter votre dépÎt Git à Vercel et de pousser votre code. Vercel détecte automatiquement votre projet Next.js et déploie vos Route Handlers en tant que fonctions sans serveur.
Techniques avancées
Edge Functions
Les Route Handlers peuvent ĂȘtre dĂ©ployĂ©s en tant que Edge Functions, qui sont exĂ©cutĂ©es Ă la pĂ©riphĂ©rie d'un CDN, plus prĂšs de vos utilisateurs. Cela peut rĂ©duire considĂ©rablement la latence et amĂ©liorer les performances.
Pour déployer un Route Handler en tant que Edge Function, ajoutez le runtime edge à votre fichier route.ts :
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from the Edge!' });
}
Server Actions
Les Server Actions vous permettent d'exécuter du code cÎté serveur directement depuis vos composants React. Les Route Handlers et les Server Actions fonctionnent parfaitement ensemble, vous permettant de construire des applications complexes avec aisance.
Voici un exemple d'utilisation d'une Server Action pour appeler un Route Handler :
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // Rafraßchir la page pour refléter les changements
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
Mise en cache
La mise en cache peut amĂ©liorer considĂ©rablement les performances de vos points de terminaison d'API. Vous pouvez utiliser l'en-tĂȘte Cache-Control pour contrĂŽler la maniĂšre dont vos rĂ©ponses sont mises en cache par les navigateurs et les CDN.
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
Cet exemple dĂ©finit l'en-tĂȘte Cache-Control sur public, max-age=3600, ce qui indique aux navigateurs et aux CDN de mettre en cache la rĂ©ponse pendant une heure.
Meilleures pratiques
- Utilisez TypeScript : Tirez parti de la sécurité des types de TypeScript pour améliorer la qualité du code et prévenir les erreurs.
- Validez les requĂȘtes : Validez les requĂȘtes entrantes pour garantir l'intĂ©gritĂ© des donnĂ©es et empĂȘcher les entrĂ©es malveillantes.
- GĂ©rez les erreurs avec Ă©lĂ©gance : Mettez en Ćuvre une gestion appropriĂ©e des erreurs pour fournir des messages d'erreur informatifs aux clients.
- SĂ©curisez vos points de terminaison : Mettez en Ćuvre l'authentification et l'autorisation pour protĂ©ger vos points de terminaison d'API.
- Utilisez des middlewares : Utilisez des middlewares pour les prĂ©occupations transversales comme l'authentification, la journalisation et la validation des requĂȘtes.
- Mettez les réponses en cache : Utilisez la mise en cache pour améliorer les performances de vos points de terminaison d'API.
- Surveillez vos API : Surveillez vos API pour identifier et résoudre rapidement les problÚmes.
- Documentez vos API : Documentez vos API pour les rendre faciles à utiliser pour d'autres développeurs. Envisagez d'utiliser des outils comme Swagger/OpenAPI pour la documentation de l'API.
Exemples concrets
Voici quelques exemples concrets de la maniĂšre dont les Route Handlers peuvent ĂȘtre utilisĂ©s :
- API E-commerce : Créez des points de terminaison d'API pour gérer les produits, les commandes et les utilisateurs.
- API de réseau social : Créez des points de terminaison d'API pour publier des tweets, suivre des utilisateurs et récupérer des chronologies.
- API de systÚme de gestion de contenu (CMS) : Créez des points de terminaison d'API pour gérer le contenu, les utilisateurs et les paramÚtres.
- API d'analyse de données : Créez des points de terminaison d'API pour collecter et analyser des données. Par exemple, un Route Handler pourrait recevoir des données de pixels de suivi sur différents sites web et agréger les informations pour le reporting.
Exemple de E-commerce international : Un Route Handler utilisĂ© pour rĂ©cupĂ©rer les prix des produits en fonction du pays de l'utilisateur. Le point de terminaison pourrait utiliser la gĂ©olocalisation de la requĂȘte (dĂ©rivĂ©e de l'adresse IP) pour dĂ©terminer l'emplacement de l'utilisateur et renvoyer les prix dans la devise appropriĂ©e. Cela contribue Ă une expĂ©rience d'achat localisĂ©e.
Exemple d'authentification globale : Un Route Handler mettant en Ćuvre l'authentification multifacteur (MFA) pour les utilisateurs du monde entier. Cela pourrait impliquer l'envoi de codes SMS ou l'utilisation d'applications d'authentification, tout en respectant les rĂ©glementations sur la confidentialitĂ© et les infrastructures de tĂ©lĂ©communication des diffĂ©rentes rĂ©gions.
Livraison de contenu multilingue : Un Route Handler qui livre le contenu dans la langue prĂ©fĂ©rĂ©e de l'utilisateur. Celle-ci peut ĂȘtre dĂ©terminĂ©e Ă partir de l'en-tĂȘte `Accept-Language` dans la requĂȘte. Cet exemple souligne la nĂ©cessitĂ© d'un encodage UTF-8 correct et du support des langues s'Ă©crivant de droite Ă gauche, le cas Ă©chĂ©ant.
Conclusion
Les Route Handlers de Next.js offrent un moyen puissant et flexible de créer des points de terminaison d'API directement au sein de votre application Next.js. En tirant parti des Route Handlers, vous pouvez construire des API robustes avec facilité, colocaliser votre logique backend avec vos composants React et profiter de fonctionnalités comme les middlewares, le streaming et les Edge Functions.
Ce guide complet a couvert tout, de la configuration de base aux techniques avancées. En suivant les meilleures pratiques décrites dans ce guide, vous pouvez construire des API de haute qualité qui sont sécurisées, performantes et maintenables.